#include <stdio.h>
#include <iostream>

#include "../include/PDTextExtractor.h"
using namespace std;
CPDTextExtractor::CPDTextExtractor()
{
	m_pDisplayMatrix = NULL;
	m_pPDParser = NULL;
	m_pLRProcessor = NULL;
}

CPDTextExtractor::~CPDTextExtractor(){
	
	if(m_pDisplayMatrix) delete m_pDisplayMatrix;
	if(m_pLRProcessor) delete m_pLRProcessor;
	if(m_pPDParser) delete m_pPDParser;

}

FX_INT32 CPDTextExtractor::StartExtract(FX_LPCWSTR lpszFile, const char* pwd)
{

	CFX_WideString wsFile(lpszFile);
	m_wsSrcFilePath = wsFile;
const wchar_t* psz= (wchar_t*)lpszFile;

	m_pPDParser = FX_NEW CPDF_Parser;

	if(NULL != pwd)
	{
		m_pPDParser->SetPassword(pwd);
	}
	FX_DWORD dw = PDFPARSE_ERROR_SUCCESS;
	try
	{
		dw = m_pPDParser->StartParse(lpszFile);

//		CFX_ByteString bs = CFX_ByteString::FromUnicode(lpszFile);
//		FX_CHAR c = '\\';

#ifdef _WIN32
//		c = '\\';
#else
//		c = '/';
#endif
/*
		int nPos = bs.ReverseFind(c);
		if(nPos > 0)
		{
			m_bsCurFile = bs.Right(bs.GetLength()-nPos-1);
		}
		*/
	}
	catch (...)
	{
		m_pPDParser->CloseParser();
		delete m_pPDParser;
		m_pPDParser = 0;
		return dw;
	}
	if(dw)
	{
		m_pPDParser->CloseParser();
		delete m_pPDParser;
		m_pPDParser = NULL;
		return dw;
	}
	
	if(NULL == m_pPDParser->GetDocument())
	{
		return -1;
	}
	FX_INT32 nPage = m_pPDParser->GetDocument()->GetPageCount();
	m_arrPageLRProcessor.SetSize(nPage);

	m_pLRProcessor = IPDFLR_DocumentProcessor::Create();
	FX_BOOL bInit = m_pLRProcessor->Initialize(m_pPDParser->GetDocument());

	return dw;
}


void CPDTextExtractor::Close()
{

	if(m_pLRProcessor)
	{
		delete m_pLRProcessor;
		m_pLRProcessor = NULL;
	}

	if(m_pPDParser)
	{
		m_pPDParser->CloseParser();
		delete m_pPDParser;
		m_pPDParser = NULL;
	}
	FX_INT32 nIndependPara = m_arrIndependPara.GetSize();
	for(FX_INT32 i=0; i<nIndependPara; i++)
	{
		INDEPENDLINEPARAGRAPH* pNode = (INDEPENDLINEPARAGRAPH*)m_arrIndependPara.GetAt(i);
		if(NULL == pNode) continue;
		
		delete pNode;
	}
	m_arrIndependPara.RemoveAll();
	m_arrPageLRProcessor.RemoveAll();

}

FX_INT32 CPDTextExtractor::CountParagraphRects(FX_INT32 iPage)
{
CFX_ByteString bs;
bs.Format("CPDTextExtractor::CountParagraphRects:entring iPage=%d\r", iPage);
gWriteLog(bs);
	IPDFLR_PageProcessor* pPageProcessor = this->GetPageLRProcessor(iPage);
	FX_INT32 n= pPageProcessor->CountParagraphs();
gWriteLog("CPDTextExtractor::CountParagraphRects:outing\r");

	return n;
}

CPDF_Rect CPDTextExtractor::GetParagraphRect(FX_INT32 iPage, FX_INT32 iRect)
{
	CPDF_Rect BBox;
gWriteLog("CPDTextExtractor::GetParagraphRect:entring\r");
	IPDFLR_PageProcessor* pPageProcessor = this->GetPageLRProcessor(iPage);
	IPDFLR_Cell* pCurParagraph = pPageProcessor->GetParagraph(iRect);	
	pCurParagraph->GetBBox(BBox);
gWriteLog("CPDTextExtractor::GetParagraphRect:outing\r");
	return BBox;


}

void CPDTextExtractor::GetObjText(CPDF_PageObject* pObj, CFX_WideString& csText)
{
	CFX_WideString wstr = L"";
	//CFX_WideString wsContent = L"";
	switch(pObj->m_Type)
	{
		case PDFPAGE_TEXT:
		{
			CPDF_TextObject* pTextObj = (CPDF_TextObject*)pObj;
			CPDF_TextObjectItem textObjItem;
			int nItemCount = pTextObj->CountItems();
			CPDF_Font* pFont = pTextObj->GetFont();
			for(int i = 0; i < nItemCount; i++)
			{
				pTextObj->GetItemInfo(i, &textObjItem);

				if(0xffffffff == textObjItem.m_CharCode)
				{
					//do nothing, wo igore it;
				}
				else
				{
					wstr = pFont->UnicodeFromCharCode(textObjItem.m_CharCode);
					
						if ((wstr.IsEmpty() || wstr.GetAt(0)==0) && textObjItem.m_CharCode)
						{
							if (wstr.IsEmpty())	
								wstr += (FX_WCHAR)textObjItem.m_CharCode;
							else
								wstr.SetAt(0, (FX_WCHAR)textObjItem.m_CharCode);
						}

						//bstr += wstr.UTF8Encode();
						csText += wstr;
					
					//this->strContent += (FX_LPCSTR)bstr;
				}
			}
		}
		break;
		case PDFPAGE_PATH:
			csText += L"";
			break;
		case PDFPAGE_IMAGE:
			csText += L"";
			break;
		case PDFPAGE_SHADING:
			csText += L"";
			break;
		case PDFPAGE_FORM:
			csText += L"";
			break;
		case PDFPAGE_INLINES:
			csText += L"";
			break;
	
	}
}
void CPDTextExtractor::ExtractParagraphContent(IPDFLR_Cell* pCell, FX_FLOAT fPageWidth, CFX_WideString& csCon)
{
gWriteLog("CPDTextExtractor::ExtractParagraphContent:entring\r");
	FX_POSITION pos = pCell->GetChildCellHeadPos();
	FX_INT32 nLevel=0;
	while(pos)
	{
		if(++nLevel > 1000) break;
		IPDFLR_Cell* pNext = pCell->GetNextChildCell(pos);
		if(NULL == pNext) continue;
		FPDFLR_AttributeType eType = pNext->GetCellType();
		if(eType == FPDFLR_AT_Baseline)
		{
			FX_INT32 nLevel2 = 0;
			FX_POSITION pos2 = pNext->GetChildCellHeadPos();
			while(pos2){
				IPDFLR_Cell* pNext2 = pNext->GetNextChildCell(pos2);
				if(pNext2)
				{
					CPDF_PageObject* pObj = pNext2->GetPageObject();
		
					if(pObj && pObj->m_Type == PDFPAGE_TEXT)
					{
						CFX_WideString ws;
						this->GetObjText(pObj, ws);
						csCon += ws;
					}
					if(++nLevel2 > 200) break;
				}
			}

		}
		
	}
gWriteLog("CPDTextExtractor::ExtractParagraphContent:outing\r");
}

FX_BOOL CPDTextExtractor::IsAllLineIndepend(FX_INT32 iPage, FX_INT32 iParagraph)
{
	IPDFLR_PageProcessor* pPageProcessor = this->GetPageLRProcessor(iPage);
	
	IPDFLR_Cell* pCurParagraph = pPageProcessor->GetParagraph(iParagraph);
	if(NULL == pCurParagraph) return FALSE;
	CPDPageParagraphInfo* pParaInfo = new CPDPageParagraphInfo(pCurParagraph);
	FX_INT32 nLineCount = 0;
	FX_BOOL bAllLineIndepend = FALSE;

	pParaInfo->GetLineIndependInfo(pPageProcessor->GetPDFPage()->GetPageWidth(), pPageProcessor->GetPDFPage()->GetPageHeight(), nLineCount, bAllLineIndepend);
	if(!bAllLineIndepend)
	{
		delete pParaInfo;
		return FALSE;
	}
	
	INDEPENDLINEPARAGRAPH* pNode = new INDEPENDLINEPARAGRAPH;
	pNode->m_iPage = iPage;
	pNode->m_iPara = iParagraph;
	pNode->m_pInfo = pParaInfo;
	m_arrIndependPara.Add(pNode);


	return TRUE;
	
}
FX_INT32 CPDTextExtractor::GetIndependLineCount(FX_INT32 iPage, FX_INT32 iParagraph)
{
	FX_INT32 nCount = m_arrIndependPara.GetSize();
	for(int i=0; i<nCount; i++)
	{
		INDEPENDLINEPARAGRAPH* pNode = (INDEPENDLINEPARAGRAPH*)m_arrIndependPara.GetAt(i);
		if(iPage == pNode->m_iPage && iParagraph == pNode->m_iPara)
		{
			FX_INT32 n = pNode->m_pInfo->GetIndependLineCount();
			return n;
		}
	}
	return 0;
}
CFX_WideString CPDTextExtractor::GetIndependLineContent(FX_INT32 iPage, FX_INT32 iParagraph, FX_INT32 iLine)
{
	FX_INT32 nCount = m_arrIndependPara.GetSize();
	for(int i=0; i<nCount; i++)
	{
		INDEPENDLINEPARAGRAPH* pNode = (INDEPENDLINEPARAGRAPH*)m_arrIndependPara.GetAt(i);

		if(iPage == pNode->m_iPage && iParagraph == pNode->m_iPara)
		{
			CFX_WideString* p = (CFX_WideString*)pNode->m_pInfo->GetLineContent(iLine);
			return *p;
		}
	}
	
	 return L"";
}

IPDFLR_Cell* CPDTextExtractor::GetIndependLineInfo(FX_INT32 iPage, FX_INT32 iParagraph, FX_INT32 iLine, CPDF_Rect& rc)
{
	FX_INT32 nCount = m_arrIndependPara.GetSize();
	for(int i=0; i<nCount; i++)
	{
		INDEPENDLINEPARAGRAPH* pNode = (INDEPENDLINEPARAGRAPH*)m_arrIndependPara.GetAt(i);
		if(iPage == pNode->m_iPage && iParagraph == pNode->m_iPara)
		{
			rc = pNode->m_pInfo->GetLineRect(iLine);
			return pNode->m_pInfo->GetLineCell(iLine);
		}
	}
	
	 return NULL;
}

IPDFLR_PageProcessor* CPDTextExtractor::GetPageLRProcessor(FX_INT32 iPage)
{

	IPDFLR_PageProcessor* pPageProcessor = (IPDFLR_PageProcessor*)m_arrPageLRProcessor.GetAt(iPage);
	if(NULL == pPageProcessor)
	{
		CPDFLR_ParseOptions parseOption;
		parseOption.m_ContentOrder = FPDFLR_PARSERFLAG_STREAM_ORDER;
		pPageProcessor = m_pLRProcessor->GetPageProcessor(iPage);
		pPageProcessor->Start(FALSE, &parseOption);
		while (pPageProcessor->Continue(NULL) == FPDFLR_ProgressiveStatus_ToBeContinued)
	 	{
	 	}
		m_arrPageLRProcessor.SetAt(iPage, pPageProcessor);

	}

return pPageProcessor;
}
CFX_WideString CPDTextExtractor::GetParagraphContent(FX_INT32 iPage, FX_INT32 iParagraph)
{
CFX_ByteString bs;
bs.Format("CPDTextExtractor::GetParagraphContent:entring iPage=%d, iPara=%d\r", iPage, iParagraph);
gWriteLog(bs);
	IPDFLR_PageProcessor* pPageProcessor = this->GetPageLRProcessor(iPage);
	IPDFLR_Cell* pCurParagraph = pPageProcessor->GetParagraph(iParagraph);
	if(NULL == pCurParagraph) return L"";

	CFX_WideString ws;
	this->ExtractParagraphContent(pCurParagraph, pPageProcessor->GetPDFPage()->GetPageWidth(), ws);
gWriteLog("CPDTextExtractor::GetParagraphContent:outing\r");
	return  ws;
}
	
void gWriteLog(CFX_ByteString bsMsg)
{
/*
	FILE *fp = NULL;
	try{
		//fopen_s(&fp, file, "a+");
		fp = fopen(LOG_FILE, "a+");
		int nLength = bsMsg.GetLength();
		if(fp)
		{
			if(fwrite((FX_LPCSTR)bsMsg, 1, nLength, fp) == 0)
			{
				fclose(fp);
				return ;
			}
			fclose(fp);
		}
	}catch(...)
	{

	}
*/
}
